package cn.wolfcode.service.impl;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AlipayFeignApi;
import cn.wolfcode.feign.IntergralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private AlipayFeignApi alipayFeignApi;
    @Autowired
    private IntergralFeignApi intergralFeignApi;

    @Override
    public String doSeckill(Integer time, Long seckillId, String phone) {
        // 库存扣减
        int count = seckillProductService.decrStockCount(seckillId);
        if (count == 0) {
            throw new BusinessException(SeckillCodeMsg.CANCEL_ORDER_ERROR);
        }
        // 生成订单
        String orderNo = createOrder(time,seckillId,phone);
        return orderNo;
    }

    @Override
    public OrderInfo queryBySeckillIdAndUserId(Long seckillId, String phone) {
        return orderInfoMapper.queryBySeckillIdAndUserId(seckillId,phone);
    }

    @Override
    public OrderInfo find(String orderNo) {
        return orderInfoMapper.find(orderNo);
    }

    @Override
    @Transactional
    public void cancelOrderAndFallbackStockCount(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        if (orderInfo != null && OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())){
            // 修改订单状态
            int effectCount = orderInfoMapper.updateCancelStatus(orderNo, OrderInfo.STATUS_TIMEOUT);
            if (effectCount > 0) { // 订单取消成功
                // 回补 mysql 库存
                seckillProductService.incrStocCount(orderInfo.getSeckillId());
                // 回补 redis 预库存
                seckillProductService.syncStockCountToRedis(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
            }else { // 订单取消失败

            }
        }
    }

    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;
    @Override
    public String payOnline(String orderNo) {
        // 查询订单 (支付宝已经做了对支付已经做了幂等同一订单不会重复支付)
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 判断订单状态
        if (!OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())) { // 超时取消的订单不可支付
            throw new BusinessException(SeckillCodeMsg.PAY_ERROR);
        }
        // 跳转支付宝页面需要携带的参数
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderInfo.getOrderNo()); // 订单编号
        payVo.setTotalAmount(String.valueOf(orderInfo.getSeckillPrice())); // 支付金额
        payVo.setSubject(orderInfo.getProductName()); // 订单标题
        payVo.setBody(orderInfo.getProductName()); // 商品详情
        payVo.setReturnUrl(returnUrl); // 同步回调地址
        payVo.setNotifyUrl(notifyUrl); // 异步回调地址
        // 远程调用支付服务,获取 html 内容
        Result<String> result = alipayFeignApi.pay(payVo);
        if (result == null || result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.PAY_ERROR);
        }
        return result.getData();
    }

    @Override
    public int updateOrderStatus2Paid(String orderNo, Integer status, Integer type) {
        return orderInfoMapper.changePayStatus(orderNo,status,type);
    }

    @Override
    public void refundOnline(OrderInfo orderInfo) {
        RefundVo refundVo = new RefundVo(); // 退款参数封装
        refundVo.setOutTradeNo(orderInfo.getOrderNo()); // 退款商户订单号
        refundVo.setRefundAmount(String.valueOf(orderInfo.getSeckillPrice())); // 退款金额
        refundVo.setRefundReason("不想要了"); // 退款理由
        // 远程调用支付服务的退款
        Result<Boolean> result = alipayFeignApi.refund(refundVo);
        if (result == null || result.hasError()) { // 远程调用支付服务失败
            throw new BusinessException(SeckillCodeMsg.PAY_SERVER_ERROR);
        }
        if (!result.getData()) { // 支付服务调用支付宝退款接口的时候退款失败
            throw new BusinessException(SeckillCodeMsg.PAY_ERROR);
        }else { // 退款完成,修改订单状态
            orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        }
    }

    @Override
    //@Transactional
    @GlobalTransactional
    public void payIntegral(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 判断当前订单是否可以支付
        if (orderInfo == null || !OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())) { // 当前订单不可支付
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_CHANGE_ERROR);
        }
        // 订单可以支付----积分支付幂等性,防止同一订单重复支付
        // 利用 t_pay_log 表,一个订单支付过后往表中插入一条新数据,利用主键唯一性保证一个订单只能支付一次
        PayLog log = new PayLog();
        log.setOrderNo(orderInfo.getOrderNo());
        log.setPayTime(new Date());
        log.setTotalAmount(orderInfo.getIntergral());
        log.setPayType(OrderInfo.PAYTYPE_INTERGRAL);
        try {
            payLogMapper.insert(log);
        }catch (Exception e) {
            throw new BusinessException(SeckillCodeMsg.PAY_REPEAT);
        }
        // 用户积分扣减
        OperateIntergralVo vo = new OperateIntergralVo(); // 用于用户积分扣减传递参数使用
        vo.setValue(orderInfo.getIntergral());
        vo.setUserId(orderInfo.getUserId());
        // 远程调用积分服务进行积分扣减
        Result result = intergralFeignApi.decrIntegral(vo);
        if (result == null || result.hasError()){ // 远程调用积分服务失败
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        // 远程调用积分服务成功
        // 积分扣减成功,修改订单状态
        int effectCount = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTERGRAL);
        if (effectCount == 0) { // 订单状态修改失败
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_CHANGE_ERROR);
        }
    }

    @Override
    //@Transactional
    @GlobalTransactional
    public void refundIntergral(OrderInfo orderInfo) {
        //保证幂等性,使用流水表的方式,防止订单重复退款
        RefundLog log = new RefundLog();
        log.setOrderNo(orderInfo.getOrderNo());
        log.setRefundAmount(orderInfo.getIntergral());
        log.setRefundReason("不想要了");
        log.setRefundTime(new Date());
        log.setRefundType(OrderInfo.PAYTYPE_INTERGRAL);
        try {
            refundLogMapper.insert(log);
        }catch (Exception e) {
            throw new BusinessException(SeckillCodeMsg.REFUND_REPEAT);
        }
        // 远程调用积分服务,增加用户积分
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        Result result = intergralFeignApi.addIntegral(vo);
        if (result == null || result.hasError()){ // 远程调用积分服务失败
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        // 修改订单状态
        int effectCount = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        if(effectCount==0){
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_CHANGE_ERROR);
        }
    }




    private String createOrder(Integer time, Long seckillId, String phone) {
        SeckillProductVo vo = seckillProductService.findFromCache(time, seckillId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderNo(String.valueOf(IdGenerateUtil.get().nextId()));
        orderInfo.setUserId(Long.valueOf(phone));
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setIntergral(vo.getIntergral());
        orderInfo.setStatus(0);
        orderInfo.setCreateDate(new Date());
        orderInfo.setSeckillDate(vo.getStartDate());
        orderInfo.setSeckillTime(time);
        orderInfo.setSeckillId(seckillId);
        try{
            // 数据库插入新订单
            int count = orderInfoMapper.insert(orderInfo);
        }catch (Exception e) {
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }
        // 同时在 redis 中写入订单创建完成的记录
        String key = SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(String.valueOf(seckillId));
        redisTemplate.opsForSet().add(key, phone);
        return orderInfo.getOrderNo();
    }
}
